package com.hedl.practice.diyJava.data.best_practices.test;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.*;

public class Study_BestPractices {
    public static void main(String[] args) {
        //旧API转新API
        /**
         * 把Date()转为心的API Instant;
         *      使用new Date().toInstant()
         * 把Calendar 转为新的 API
         *      先创建Calendar.getInstance()实例
         * 先转为时区
         */
        Instant instant = new Date().toInstant();

        Instant is = Calendar.getInstance().toInstant();
        System.out.println("旧转新："+is);

        Date date = Date.from(Instant.now());
        System.out.println(date);

        LocalDateTime localDateTime = LocalDateTime.now();
        ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.systemDefault());
        Calendar calendar = GregorianCalendar.from(zonedDateTime);
        System.out.println("默认本地化日期时间："+localDateTime);
        System.out.println("默认本机时区："+zonedDateTime);

        /**
         * 新API转旧API
         *
         */
        // ZonedDateTime -> long:
        ZonedDateTime zdt = ZonedDateTime.now();
        long l = zdt.toEpochSecond() * 1000;

        // long -> Date:
        Date d = new Date(l);
        System.out.println("新API转旧API时间："+d);

        // long -> Calendar:
        Calendar calendar1 = Calendar.getInstance();
        calendar1.clear();
        calendar1.setTimeZone(TimeZone.getTimeZone(zdt.getZone().getId()));
        calendar1.setTimeInMillis(zdt.toEpochSecond()*1000);
        System.out.println("旧转新："+calendar1.toInstant());
        /**
         * 从上面的代码还可以看到，新的ZoneId转换为旧的TimeZone，需要借助ZoneId.getId()返回的String完成。
         */

        System.out.println("============================================");

        /**
         * 在数据库中存储日期和时间
         *      在数据库中，也存在几种日期和时间类型：
         *          DATETIME：表示日期和时间；
         *          DATE：仅表示日期；
         *          TIME：仅表示时间；
         *          TIMESTAMP：和DATETIME类似，但是数据库会在创建或者更新记录的时候同时修改TIMESTAMP。
         *
         * 下表是数据库类型与Java新旧API的映射关系：
         *
         * 数据库	                                对应Java类（旧）	                                     对应Java类（新）
         * DATETIME	                                java.util.Date	                                    LocalDateTime
         * DATE	                                    java.sql.Date	                                    LocalDate
         * TIME	                                    java.sql.Time	                                    LocalTime
         * TIMESTAMP	                            java.sql.Timestamp	                                LocalDateTime
         *
         *      实际上，在数据库中，我们需要存储的最常用的是时刻（Instant），因为有了时刻信息，就可以根据用户自己选择的时区，
         *      显示出正确的本地时间。所以，最好的方法是直接用长整数long表示，在数据库中存储为BIGINT类型。
         *
         *
         *
         */
        //通过存储一个long型时间戳，我们可以编写一个timestampToString()的方法，非常简单地为不同用户以不同的偏好来显示不同的本地时间：
        long ts = 1574208900000L;
        System.out.println(timestampToString(ts, Locale.CHINA,"Asia/Shanghai"));
        System.out.println(timestampToString(ts,Locale.US,"America/New_York"));
    }

    /**
     * 小结：
     *      处理日期和时间时，尽量使用新的java.time包；
     *      在数据库中存储时间戳时，尽量使用long型时间戳，它具有省空间，效率高，不依赖数据库的优点。
     * @param ts
     * @param lo
     * @param s
     * @return
     */
    private static String timestampToString(long ts, Locale lo, String s) {
        Instant ins = Instant.ofEpochMilli(ts);     //传入时间戳
        DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM,FormatStyle.SHORT);
        return f.withLocale(lo).format(ZonedDateTime.ofInstant(ins,ZoneId.of(s)));

    }

}
